= chess-data

Install from {RubyGems}[https://rubygems.org/gems/chess-data/]:

  > gem install chess-data

source:: {chess-data.zip}[http://peterlane.info/downloads/chess-data.zip]

== Description

For searching/filtering datasets of chess games.

Features

* Read and save collections of PGN files
* Filter games looking for games containing positions with certain combinations 
  of pieces
* Save collections of PGN games or individual positions after filtering.
* PGN lexer follows specification in https://www.chessclub.com/help/PGN-spec
  * note that the lexer recognises but ignores comments and NAGs, so they will 
    not appear in any resaved games

== Position Definitions

Games are stored in an instance of +ChessData+::+Database+, and can be filtered using 
the +search+ method.  The search method takes a block defining the numbers of pieces of 
each type and returns a new database containing just those games which match the 
definition.  For example, the following filters for 5-4 rook endings:

  rook_endings_database = database.search do
    exactly 1, "R", "r"
    exactly 5, "P"
    exactly 4, "p"
  end

Filters include:

* 'exactly n, *pieces' 
* 'at_least n, *pieces'
* 'at_most n, *pieces'

== Example: Extracting all 5-4 R+P endings

  # Read database of games and query
   
  require 'chess-data'
  
  # create a database
  database = ChessData::Database.new
  
  # read in pgn files provided on command line and add them to the database
  ARGV.each do |file|
    puts "Reading from #{file}"
    database.add_games_from file
  end
  
  # extract those games which at some point reach given position definition
  selected = database.search do
    exactly 1, "R", "r"
    exactly 5, "P"
    exactly 4, "p"
  end
  
  # report and save result
  puts "Found #{selected.size} games"
  selected.to_file "selected.pgn"
  
  puts "Selected #{selected.size} out of #{database.size}"
 
== Example: Study a game move-by-move

The ChessData::Game#play_game method takes a block, which is passed the current
board and next move after each half move. The following example prints out the
board position and information to create a trace of the game:

  $game.play_game do |board, next_move|
    puts board.to_s
    puts
    puts "Move #{board.fullmove_number}: #{if board.to_move == "w" then "" else "... " end}#{next_move}"
  end

Sample output:

  Move 32: Rxd7+
  ........
  ..kR...p
  ....pb.Q
  ........
  ..P..Pq.
  .Pn.....
  ......P.
  ......BK
  
  Move 32: ... Kxd7
  ........
  ...k...p
  ....pb.Q
  ........
  ..P..Pq.
  .Pn.....
  ......P.
  ......BK
  
  Move 33: Qxf6
  ........
  ...k...p
  ....pQ..
  ........
  ..P..Pq.
  .Pn.....
  ......P.
  ......BK
  
  Move 33: ... 1/2-1/2

